<template>
    <div class="dv-scroll-ranking-board1" :ref="ref">
        <div class="row-item"
             v-for="(item, i) in rows"
             :key="item.toString() + item.scroll"
             :style="`height: ${heights[i]}px;`">
            <div class="ranking-info">
                <!--        <div class="rank">No.{{ item.ranking }}</div>-->
                <div class="info-name" v-html="item.name" :style="{...mergedConfig.nameStyle}"/>
                <div class="ranking-column" :style="{marginTop:mergedConfig.barTop}">
                    <div class="background-column" v-if="mergedConfig.showBack" :style="{height:mergedConfig.barHeight,borderRadius:mergedConfig.barRadius,...mergedConfig.backBarStyle}"/>
                    <div class="inside-column"
                         :style="{width: `${item.percent}%`,borderRadius:mergedConfig.barRadius,height:mergedConfig.barHeight,...mergedConfig.barStyle}">
                        <div class="shine"/>
                    </div>
                </div>
                <div class="ranking-value" :style="{...mergedConfig.valueStyle}">{{ item.value + mergedConfig.unit }}</div>
            </div>
        </div>
    </div>
</template>

<script>
  import autoResize from '../../../mixin/autoResize'

  import {deepMerge} from '@jiaminghi/charts/lib/util/index'

  import {deepClone} from '@jiaminghi/c-render/lib/plugin/util'

  export default {
    name: 'DvScrollRankingBoard1',
    mixins: [autoResize],
    props: {
      config: {
        type: Object,
        default: () => ({})
      }
    },
    data() {
      return {
        ref: 'scroll-ranking-board',

        defaultConfig: {
          /**
           * @description Board data
           * @type {Array<Object>}
           * @default data = []
           */
          data: [],
          /**
           * @description Row num
           * @type {Number}
           * @default rowNum = 5
           */
          rowNum: 5,
          /**
           * @description Scroll wait time
           * @type {Number}
           * @default waitTime = 2000
           */
          waitTime: 2000,
          /**
           * @description Carousel type
           * @type {String}
           * @default carousel = 'single'
           * @example carousel = 'single' | 'page'
           */
          carousel: 'single',
          /**
           * @description Value unit
           * @type {String}
           * @default unit = ''
           * @example unit = 'ton'
           */
          unit: '',
          /**
           * @description Auto sort by value
           * @type {Boolean}
           * @default sort = true
           */
          sort: true,
          nameStyle:{
            color: "#00ff00",
            width:'100px'
          },
          valueStyle:{
            color: "#00ff00",
            width:'100px'
          },
          barRadius:'5px',
          barHeight:'10px',
          barTop:'5px',
          /**
           * @description 柱形条样式
           *  @type {Object}
           *  @default barStyle = {backgroundImage:`linear-gradient(to right, blue , yellow)`}
           */
          barStyle:{
            background:`linear-gradient(to right, red , yellow)`,
          },
          showBack:true,
          backBarStyle:{
            background:'#666',
          },
        },

        mergedConfig: null,

        rowsData: [],

        rows: [],

        heights: [],

        animationIndex: 0,

        animationHandler: '',

        updater: 0
      }
    },
    watch: {
      config:{
        handler:function() {
            const {stopAnimation, calcData} = this

            stopAnimation()

            calcData()
          },
        deep:true
      }
    },
    methods: {
      afterAutoResizeMixinInit() {
        const {calcData} = this

        calcData()
      },
      onResize() {
        const {mergedConfig, calcHeights} = this

        if (!mergedConfig) return

        calcHeights(true)
      },
      calcData() {
        const {mergeConfig, calcRowsData} = this

        mergeConfig()

        calcRowsData()

        const {calcHeights} = this

        calcHeights()

        const {animation} = this

        animation(true)
      },
      mergeConfig() {
        let {config, defaultConfig} = this

        this.mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {})
      },
      calcRowsData() {
        let {data, rowNum, sort} = this.mergedConfig

        sort && data.sort(({value: a}, {value: b}) => {
          if (a > b) return -1
          if (a < b) return 1
          if (a === b) return 0
        })

        const value = data.map(({value}) => value)

        const max = Math.max(...value) || 0

        data = data.map((row, i) => ({...row, ranking: i + 1, percent: row.value / max * 100}))

        const rowLength = data.length

        if (rowLength > rowNum && rowLength < 2 * rowNum) {
          data = [...data, ...data]
        }

        data = data.map((d, i) => ({...d, scroll: i}))

        this.rowsData = data
        this.rows = data
      },
      calcHeights(onresize = false) {
        const {height, mergedConfig} = this

        const {rowNum, data} = mergedConfig

        const avgHeight = height / rowNum

        this.avgHeight = avgHeight

        if (!onresize) this.heights = new Array(data.length).fill(avgHeight)
      },
      async animation(start = false) {
        let {avgHeight, animationIndex, mergedConfig, rowsData, animation, updater} = this

        const {waitTime, carousel, rowNum} = mergedConfig

        const rowLength = rowsData.length

        if (rowNum >= rowLength) return

        if (start) {
          await new Promise(resolve => setTimeout(resolve, waitTime))
          if (updater !== this.updater) return
        }

        const animationNum = carousel === 'single' ? 1 : rowNum

        let rows = rowsData.slice(animationIndex)
        rows.push(...rowsData.slice(0, animationIndex))

        this.rows = rows
        this.heights = new Array(rowLength).fill(avgHeight)

        await new Promise(resolve => setTimeout(resolve, 300))
        if (updater !== this.updater) return

        this.heights.splice(0, animationNum, ...new Array(animationNum).fill(0))

        animationIndex += animationNum

        const back = animationIndex - rowLength
        if (back >= 0) animationIndex = back

        this.animationIndex = animationIndex
        this.animationHandler = setTimeout(animation, waitTime - 300)
      },
      stopAnimation() {
        const {animationHandler, updater} = this

        this.updater = (updater + 1) % 999999

        if (!animationHandler) return

        clearTimeout(animationHandler)
      }
    },
    destroyed() {
      const {stopAnimation} = this

      stopAnimation()
    }
  }
</script>

<style lang="less">
    @color: #1370fb;

    .dv-scroll-ranking-board1 {
        width: 100%;
        height: 100%;
        color: #fff;
        overflow: hidden;

        .row-item {
            transition: all 0.3s;
            display: flex;
            flex-direction: column;
            justify-content: center;
            overflow: hidden;
        }

        .ranking-info {
            display: flex;
            width: 100%;
            font-size: 13px;

            .rank {
                width: 40px;
                color: @color;
            }

            .info-name {
                /*flex: 1;*/
                text-align: right;
                padding-right: 10px;
                width: 100px;
            }

            .ranking-column {
                position: relative;
                flex: 1;
                vertical-align: middle;
                .background-column {
                    position: absolute;
                    width: 100%;
                    height: 10px;
                    top: 0;
                    /*background: radial-gradient(rgb(40, 248, 255) 5%, transparent 80%);*/
                    background: #ccc;
                }
                .inside-column {
                    position: relative;
                    height: 6px;
                    background-color: @color;
                    margin-bottom: 2px;
                    border-radius: 1px;
                    overflow: hidden;
                }

                .shine {
                    position: absolute;
                    left: 0%;
                    top: 2px;
                    height: 2px;
                    width: 50px;
                    transform: translateX(-100%);
                    background: radial-gradient(rgb(40, 248, 255) 5%, transparent 80%);
                    animation: shine 3s ease-in-out infinite alternate;
                }
            }
            .ranking-value {
                width: 100px;
            }
        }
    }

    @keyframes shine {
        80% {
            left: 0%;
            transform: translateX(-100%);
        }

        100% {
            left: 100%;
            transform: translateX(0%);
        }
    }
</style>
